#include <math.h>
#include <iostream>
#include <functional>

using std::cout;
using std::endl;
using std::function;
using std::bind;
using std::string;


class Figure
{
public:
    using DisplayCallback=function<string()>;
    using AreaCallback=function<double()>;

    //设置函数对象(设置回调函数)
    void setDisplayCallback(DisplayCallback && cb)
    {
        _displayCallback = std::move(cb);
    }

    void setAreaCallback(AreaCallback && cb)
    {
        _areaCallback = std::move(cb);
    }

    //调用函数对象(调用回调函数)
    string handleDisplayCallback()  {
        if(_displayCallback) {
            return _displayCallback();
        }
        return string();
    }

    double handleAreaCallback() {
        if(_areaCallback) {
            return _areaCallback();
        }
        return 0;
    }
private:
    function<string()> _displayCallback;//回调函数
    function<double()> _areaCallback;//变量
};

void display(Figure & fig)
{
    cout << fig.handleDisplayCallback();
    cout << "的面积为" << fig.handleAreaCallback() << endl;
}

class Circle
{
public:
    Circle(double radius)
    : _radius(radius)
    {}

    string getName() const
    {   return string("cirlce");    }

    double getArea() const 
    {   return 3.14 * _radius * _radius;    }
private:
    double _radius;
};

class Rectangle
{//没有继承
public:
    Rectangle(double l, double w)
    : _length(l)
    , _width(w)
    {}

    //函数名字可以随便取
    string name() const
    {   return string("rectangle"); }

    double area() const
    {   return _length * _width;    }

private:
    double _length;
    double _width;
};

class Triangle
{
public:
    Triangle(double a, double b, double c)
    : _a(a), _b(b), _c(c)
    {}

    string showName() const
    {   return string("triangle");  }

    double calcArea() const
    {
        double p = (_a + _b + _c) / 2;
        return sqrt(p * (p - _a) * (p - _b) * (p - _c));    
    }

private:
    double _a, _b, _c;
};

int main()
{
    Figure fig;//具体类,不是抽象类
    Circle circle(10);//Circle与Figure没有继承关系
    Rectangle rectangle(10, 20);
    Triangle triangle(3, 4, 5);

    //circle.getName();
    //circle.getArea();

    //直接设置相应的函数对象(注册函数对象)
    fig.setDisplayCallback(std::bind(&Circle::getName, &circle));
    fig.setAreaCallback(std::bind(&Circle::getArea, &circle));
    display(fig);//接口

    //修改函数对象即可
    fig.setDisplayCallback(std::bind(&Rectangle::name, &rectangle));
    fig.setAreaCallback(std::bind(&Rectangle::area, &rectangle));
    display(fig);//接口不变

    fig.setDisplayCallback(std::bind(&Triangle::showName, &triangle));
    fig.setAreaCallback(std::bind(&Triangle::calcArea, &triangle));
    display(fig);

    return 0;
}

